package services

import (
	"context"
	"fmt"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/foundation/plat-echo/pkg/utils/data"
	"go.uber.org/zap"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	"regexp"
	"strconv"
	"strings"
)

type K8sService interface {
	DeleteAlertResource(ctx context.Context, name string) error
	UpdateAlertResource(ctx context.Context, name string, graph []*models.Graph) error
	UpdateAlertResourceByTemplate(ctx context.Context, name string, template []*models.Template) error
}

type k8sService struct {
	dynamicClient dynamic.Interface
	logger        *zap.Logger
}

func NewK8SService(dynamicClient dynamic.Interface, logger *zap.Logger) K8sService {
	return &k8sService{
		logger:        logger.With(zap.String("type", "service.k8sService")),
		dynamicClient: dynamicClient,
	}
}

//删除某资源
func (s *k8sService) DeleteAlertResource(ctx context.Context, name string) error {
	defer func() {
		if r := recover(); r != nil {
			s.logger.Error("recover DeleteAlertResource")
			fmt.Println(r)
		}
	}()
	name = "prometheus-" + name + "-rules"
	resource := schema.GroupVersionResource{
		Group:    "monitoring.coreos.com",
		Version:  "v1",
		Resource: "prometheusrules",
	}
	err := s.dynamicClient.Resource(resource).Namespace("thanos").Delete(name, &metav1.DeleteOptions{})
	if err != nil {
		return errors.Wrap(err, "k8s delete resource error")
	}
	return nil
}

//name是规则名字，分别位appname,api-ApiId,hostID,dashboardID    kind为对应类型0：app 1：api 2：ip,3:dashboardID
func (s *k8sService) UpdateAlertResource(ctx context.Context, name string, graphs []*models.Graph) error {
	defer func() {
		if r := recover(); r != nil {
			s.logger.Error("recover UpdateAlertResource")
			fmt.Println(r)
		}
	}()
	namespace := viper.GetString("namespace")
	role := viper.GetString("prometheus.role")
	resource := schema.GroupVersionResource{
		Group:    "monitoring.coreos.com",
		Version:  "v1",
		Resource: "prometheusrules",
	}

	var ruleMap []map[string]interface{}

	for _, graph := range graphs {
		rule := graph.Alert

		if !rule.ValidateAlert() {
			continue
		}

		expression := strings.TrimSpace(rule.Expression)
		if strings.HasSuffix(expression, "%s") {
			expression = strings.ReplaceAll(expression, "%s", "")
		}
		//过滤不合理正则
		if strings.Contains(expression, "~\"\"") {
			s.logger.Info("跳过规则：" + expression)
			continue
		}

		ruleMap = append(ruleMap, map[string]interface{}{
			"alert": graph.Name,
			"expr":  expression + rule.Threshold,
			"for":   strconv.Itoa(rule.For) + "m",
			"labels": map[string]interface{}{
				"template_id":  strconv.Itoa(int(graph.TemplateId)),
				"name":         name,
				"app_id":       strconv.Itoa(int(graph.AppID)),
				"dashboard_id": strconv.Itoa(int(graph.DashboardID)),
				"kind":         strconv.Itoa(int(graph.Kind)),
				"graph_id":     strconv.Itoa(int(graph.ID)),
			},
			"annotations": map[string]interface{}{
				"message": rule.Message,
				"value":   "{{ $value }}",
			},
		})
	}
	if len(ruleMap) == 0 {
		return nil
	}

	name = "prometheus-" + name + "-rules"

	conf := make(map[string]interface{})
	conf = map[string]interface{}{
		"apiVersion": "monitoring.coreos.com/v1",
		"kind":       "PrometheusRule",
		"metadata": map[string]interface{}{
			"name":      name,
			"namespace": namespace,
			"labels": map[string]interface{}{
				"prometheus": "k8s",
				"role":       role,
			},
		},
		"spec": map[string]interface{}{
			"groups": []map[string]interface{}{
				{
					"name":  fmt.Sprintf("./%s.rules", name),
					"rules": ruleMap,
				},
			},
		},
	}

	err := s.dynamicClient.Resource(resource).Namespace(namespace).Delete(name, &metav1.DeleteOptions{})
	if err != nil {
		s.logger.Error("delete resource error", zap.Error(err))
	}
	obj := unstructured.Unstructured{Object: conf}
	_, err = s.dynamicClient.Resource(resource).Namespace(namespace).Create(&obj, metav1.CreateOptions{})
	if err != nil {
		s.logger.Error("update resource error", zap.Error(err))
		return err
	}
	s.logger.Info("update resource success, " + name)
	return nil
}

//根据模版直接写入k8s rules,目前只有api使用
//name是规则名字，分别位appname,api-ApiId,hostID,dashboardID    kind为对应类型0：app 1：api 2：ip,3:dashboardID
func (s *k8sService) UpdateAlertResourceByTemplate(ctx context.Context, name string, templates []*models.Template) error {
	defer func() {
		if r := recover(); r != nil {
			s.logger.Error("recover UpdateAlertResource")
			fmt.Println(r)
		}
	}()
	namespace := viper.GetString("namespace")
	role := viper.GetString("prometheus.role")
	resource := schema.GroupVersionResource{
		Group:    "monitoring.coreos.com",
		Version:  "v1",
		Resource: "prometheusrules",
	}

	var ruleMap []map[string]interface{}

	for _, template := range templates {
		rule := template.Alert

		if !rule.ValidateAlert() {
			continue
		}

		expression := strings.TrimSpace(rule.Expression)
		if strings.HasSuffix(expression, "%s") {
			expression = strings.ReplaceAll(expression, "%s", "")
		}
		//过滤不合理正则
		if strings.Contains(expression, "~\"\"") {
			s.logger.Info("跳过规则：" + expression)
			continue
		}
		arr := data.MatchApi(expression)
		if len(arr) == 0 {
			continue
		}
		for _, a := range arr {
			expression = strings.ReplaceAll(expression, a, "")
		}
		reg := regexp.MustCompile(",\\s*\\}")
		mat := reg.FindAllString(expression, -1)
		for _, a := range mat {
			expression = strings.ReplaceAll(expression, a, "}")
		}
		ruleMap = append(ruleMap, map[string]interface{}{
			"alert": template.Name,
			"expr":  expression + rule.Threshold,
			"for":   strconv.Itoa(rule.For) + "m",
			"labels": map[string]interface{}{
				"template_id": strconv.Itoa(int(template.ID)),
				"name":        name,
				"kind":        strconv.Itoa(int(template.Kind)),
			},
			"annotations": map[string]interface{}{
				"message": rule.Message,
				"value":   "{{ $value }}",
			},
		})
	}
	if len(ruleMap) == 0 {
		return nil
	}

	name = "prometheus-" + name + "-rules"

	conf := make(map[string]interface{})
	conf = map[string]interface{}{
		"apiVersion": "monitoring.coreos.com/v1",
		"kind":       "PrometheusRule",
		"metadata": map[string]interface{}{
			"name":      name,
			"namespace": namespace,
			"labels": map[string]interface{}{
				"prometheus": "k8s",
				"role":       role,
			},
		},
		"spec": map[string]interface{}{
			"groups": []map[string]interface{}{
				{
					"name":  fmt.Sprintf("./%s.rules", name),
					"rules": ruleMap,
				},
			},
		},
	}

	err := s.dynamicClient.Resource(resource).Namespace(namespace).Delete(name, &metav1.DeleteOptions{})
	if err != nil {
		s.logger.Error("delete resource error", zap.Error(err))
	}
	obj := unstructured.Unstructured{Object: conf}
	_, err = s.dynamicClient.Resource(resource).Namespace(namespace).Create(&obj, metav1.CreateOptions{})
	if err != nil {
		s.logger.Error("update resource error", zap.Error(err))
		return err
	}
	s.logger.Info("update resource success, " + name)
	return nil
}
